package com.ly.user_system.service.impl;

import com.ly.user_system.base.BaseServiceImpl;
import com.ly.user_system.base.BaseUserDetails;
import com.ly.user_system.common.CommonConstant;
import com.ly.user_system.detail.BaseSysUserDetail;
import com.ly.user_system.dto.BaseSysUserDTO;
import com.ly.user_system.dto.UserLoginDto;
import com.ly.user_system.entity.BaseSysDepartment;
import com.ly.user_system.entity.BaseSysUser;
import com.ly.user_system.exception.ExceptionEnums;
import com.ly.user_system.mapper.BaseSysUserMapper;
import com.ly.user_system.req.BaseSysUserQuery;
import com.ly.user_system.req.UserLoginReq;
import com.ly.user_system.service.BaseSysDepartmentService;
import com.ly.user_system.service.BaseSysPermsService;
import com.ly.user_system.service.BaseSysUserService;
import com.ly.user_system.utils.ConvertUtil;
import com.ly.user_system.utils.UserContextUtil;
import jakarta.annotation.Resource;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.oauth2.jwt.Jwt;
import org.springframework.security.oauth2.jwt.JwtClaimsSet;
import org.springframework.security.oauth2.jwt.JwtEncoder;
import org.springframework.security.oauth2.jwt.JwtEncoderParameters;
import org.springframework.security.provisioning.UserDetailsManager;
import org.springframework.stereotype.Service;

import java.time.Instant;
import java.time.temporal.ChronoUnit;
import java.util.List;
import java.util.function.Function;
import java.util.stream.Collectors;

@Service
public class BaseSysUserServiceImpl extends BaseServiceImpl<BaseSysUser, BaseSysUserDetail, BaseSysUserDTO, BaseSysUserQuery, BaseSysUserMapper> implements BaseSysUserService, UserDetailsManager {

    @Resource
    private BaseSysPermsService permsService;

    @Resource
    private PasswordEncoder passwordEncoder;

    @Resource
    private BaseSysDepartmentService departmentService;


    @Resource
    private JwtEncoder jwtEncoder;

    @Override
    protected void init(Class<BaseSysUser> entityClass, Class<BaseSysUserDTO> dtoClass, Class<BaseSysUserDetail> detailClass, Function<BaseSysUser, BaseSysUserDetail> detailFunction) {
        super.init(BaseSysUser.class, BaseSysUserDTO.class, BaseSysUserDetail.class, detailFunction);
    }


    @Override
    public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
        BaseSysUser user = ExceptionEnums.NOT_FIND_DATA.applyObj(queryEntity(query -> query.eq(BaseSysUser::getUsername, username)));
        List<SimpleGrantedAuthority> authorityList = permsService.getPerms(user.getId()).stream().map(SimpleGrantedAuthority::new).collect(Collectors.toList());
        return new BaseUserDetails(user, authorityList);
    }


    @Override
    public Boolean saveBatch(List<BaseSysUserDTO> list) {

        return super.saveBatch(list);
    }

    @Override
    public UserLoginDto login(UserLoginReq req) {
        // 校验信息  todo 后续增加验证码等校验信息
        BaseUserDetails userDetails = (BaseUserDetails) loadUserByUsername(req.getUserName());
        ExceptionEnums.USER_HAS_EXPIRED.apply(userDetails.isAccountNonExpired());
        ExceptionEnums.ERROR_PASSWORD.apply(userDetails.isCredentialsNonExpired());
        ExceptionEnums.USER_HAS_LOCKED.apply(userDetails.isAccountNonLocked());
        ExceptionEnums.USER_NOT_ENABLED.apply(userDetails.isEnabled());
        ExceptionEnums.ERROR_PASSWORD.apply(passwordEncoder.matches(req.getPassword(), userDetails.getPassword()));
        // 生成token
        JwtClaimsSet claimsSet = JwtClaimsSet.builder()
                .claims(jwtParam -> {
                    jwtParam.put(CommonConstant.JWT_USER_ID, userDetails.getUserId());
                    jwtParam.put(CommonConstant.JWT_USER_NAME, userDetails.getUsername());
                })
                .expiresAt(Instant.now().plus(1, ChronoUnit.DAYS))
                .build();
        JwtEncoderParameters parameters = JwtEncoderParameters.from(claimsSet);
        Jwt jwt = jwtEncoder.encode(parameters);

        return UserLoginDto.builder()
                .token(jwt.getTokenValue())
                .refreshToken(null)
                .tokenExpire(CommonConstant.EXPIRE_TIME)
                .refreshExpire(CommonConstant.EXPIRE_TIME)
                .build();
    }

    @Override
    public BaseSysUserDetail getSelfDetail() {
        BaseUserDetails principal = (BaseUserDetails) UserContextUtil.getUserContext().getPrincipal();
        BaseSysUser user = queryEntity(userQuery -> userQuery.eq(BaseSysUser::getId, principal.getUserId()));
        BaseSysUserDetail detail = ConvertUtil.convert(user, BaseSysUserDetail.class);
        detail.setRoleIdList(permsService.getRolesByUserId(user.getId()));
        detail.setDepartmentName(departmentService.queryEntityWithFunction(query -> query.eq(BaseSysDepartment::getId, detail.getDepartmentId()), BaseSysDepartment::getName));
        detail.setPassword(null);
        detail.setPasswordV(null);
        return detail;
    }


    @Override
    public void createUser(UserDetails user) {
        return;
    }

    @Override
    public void updateUser(UserDetails user) {
        return;
    }

    @Override
    public void deleteUser(String username) {
        return;
    }

    @Override
    public void changePassword(String oldPassword, String newPassword) {
        return;
    }

    @Override
    public boolean userExists(String username) {
        return false;
    }


}